#ifndef __DLIST_H
#define __DLIST_H
#include "stdtype.h"

/* check whether only single node in the list */
#define mx_dlist_isalone(l) (((mx_dlist_pt)(l))->next == (mx_dlist_pt)l)

/* get next dlist */
#define mx_dlist_next(l) (((mx_dlist_pt)(l))->next)

/* get prev dlist */
#define mx_dlist_prev(l) (((mx_dlist_pt)(l))->prev)

/**
 * this function will iterate the specified double list
 * @prototype: void mx_dlist_foreach (mx_dlist_pt, <l>, {...});
 * @note: do not change the struct of double list, such as remove or insert nodes
 */
#define mx_dlist_foreach(sl, l, ...) {   \
    mx_dlist_pt l;  \
    mx_bool_t flag = mx_true; \
    for (l = (sl); l != (sl) || ({mx_bool_t rf = flag; flag = mx_false; rf;}); l = l->next) {   \
        __VA_ARGS__    \
    }   \
}

/**
 * this function will iterate the specified double list (order -> prev)
 * @prototype: void mx_dlist_foreach_prev (mx_dlist_pt, <l>, {...});
 * @note: do not change the struct of double list, such as remove or insert nodes
 */
#define mx_dlist_foreach_prev(sl, l, ...) {   \
    mx_dlist_pt l;  \
    mx_bool_t flag = mx_true; \
    for (l = (sl); l != (sl) || ({mx_bool_t rf = flag; flag = mx_false; rf;}); l = l->prev) {   \
        __VA_ARGS__    \
    }   \
}

/**
 * this function will iterate the specified double list and the current node can be removed
 * @prototype: void mx_dlist_foreach_removable (mx_dlist_pt, <l>, {...});
 */
#define mx_dlist_foreach_removable(sl, l, ...) {    \
    mx_dlist_pt l;  \
    mx_dlist_pt nl;  \
    mx_bool_t flag = mx_true; \
    for (l = (sl); l != (sl) || ({mx_bool_t rf = flag; flag = mx_false; rf;}); l = nl) {   \
        nl = l->next;   \
        __VA_ARGS__    \
    }   \
}

/* double list definition */
typedef struct mx_dlist
{
    struct mx_dlist* prev;
    struct mx_dlist* next;
} mx_dlist_t, *mx_dlist_pt;

/* double link list init */
void mx_dlist_init (mx_dlist_pt l);
/* insert the node before the specified double list node */
void mx_dlist_insert_before (mx_dlist_pt tl, mx_dlist_pt l);
/* insert the node after the specified double list node */
void mx_dlist_insert_after (mx_dlist_pt tl, mx_dlist_pt l);
/* remove the specified double list node */
void mx_dlist_remove (mx_dlist_pt l);
/* get the count of double list */
mx_usize_t mx_dlist_count (mx_dlist_pt tl);

#endif
